//
//  BundleUtils.swift
//
//  Created by Ink on 2024/7/13.
//  Copyright © 2024 ZM. All rights reserved.
//

import Foundation


//-----------------------------------------------------------------------------------------------------------------------------------------------
public class ZMRuntime {

    //-------------------------------------------------------------------------------------------------------------------------------------------
    public static func allClasses() -> [AnyClass] {

        let numberOfClasses = Int(objc_getClassList(nil, 0))
        if numberOfClasses > 0 {
            let classesPtr = UnsafeMutablePointer<AnyClass>.allocate(capacity: numberOfClasses)
            let autoreleasingClasses = AutoreleasingUnsafeMutablePointer<AnyClass>(classesPtr)
            let count = objc_getClassList(autoreleasingClasses, Int32(numberOfClasses))
            assert(numberOfClasses == count)
            defer { classesPtr.deallocate() }
            let classes = (0 ..< numberOfClasses).map { classesPtr[$0] }
            return classes
        }
        return []
    }

    //-------------------------------------------------------------------------------------------------------------------------------------------
    public static func subclasses(of `class`: AnyClass) -> [AnyClass] {

        return self.allClasses().filter {
            var ancestor: AnyClass? = $0
            while let type = ancestor {
                if ObjectIdentifier(type) == ObjectIdentifier(`class`) { return true }
                ancestor = class_getSuperclass(type)
            }
            return false
        }
    }

    //-------------------------------------------------------------------------------------------------------------------------------------------
    public static func classes(conformToProtocol `protocol`: Protocol) -> [AnyClass] {

        let classes = self.allClasses().filter { aClass in
            var subject: AnyClass? = aClass
            while let aClass = subject {
                if class_conformsToProtocol(aClass, `protocol`) { return true }
                subject = class_getSuperclass(aClass)
            }
            return false
        }
        return classes
    }

    //-------------------------------------------------------------------------------------------------------------------------------------------
    public static func classes<T>(conformTo: T.Type) -> [T] {
        return self.allClasses().compactMap { $0 as? T }
    }
}

extension Bundle {
    
//    // 所有的类 need long time(使用的时候需要注意)
//    public class func allClasses<R>(
//        _ body: (UnsafeBufferPointer<AnyClass>) throws -> R
//    ) rethrows -> R {
//        var count: UInt32 = 0
//        let classListPtr = objc_copyClassList(&count)
//        defer {
//            free(UnsafeMutableRawPointer(classListPtr))
//        }
//        let classListBuffer = UnsafeBufferPointer(
//            start: classListPtr, count: Int(count)
//        )
//        
//        return try body(classListBuffer)
//    }
    
    // bundle内所有的类
    public func allClasses<R>(_ body: ([AnyClass]) throws -> R
    ) rethrows -> R {
        return try Self.allClasses(executablePath: self.executablePath,body)
    }
    
    public static func allClasses<R>(cla:AnyClass,
                              _ body: ([AnyClass]) throws -> R
    ) rethrows -> R {
        return try allClasses(executablePath: class_getImageName(cla.self),body)
    }
    
    static func allClasses<R>(executablePath: UnsafePointer<CChar>?,
        _ body: ([AnyClass]) throws -> R
    ) rethrows -> R {
        
//        var parsedClass = [AnyClass]()
//        var size: UInt32 = 0
//        if let executablePath = executablePath,
//            let rawClassNames = objc_copyClassNamesForImage(executablePath, &size) {
//            for i in 0..<Int(size) {
//                if let cla = NSClassFromString(String(cString: rawClassNames[i])) {
//                    parsedClass.append(cla)
//                }
//            }
//            free(rawClassNames)
//        }
//        else {
//            print("无法获取附件的类列表")
//        }
        
        let parsedClass = ZMRuntime.allClasses()
        return try body(parsedClass)
    }
}
